Imports System
Imports System.IO
Imports System.Text

''' <summary>
''' Methods to handle IO operations and file system information.
''' </summary>
Public Class IOUtil

#Region "Private constructor"

	Private Sub New()
		' Can't create instance!
	End Sub

#End Region

#Region "Validation"

	''' <summary>
	''' Checks if the specified value is a valid path.
	''' </summary>
	''' <returns>True if a valid path, otherwise False.</returns>
	Public Shared Function ValidatePath(ByVal value As String) As Boolean

		Dim objChar As Char

		If value Is Nothing Then
			Return False
		ElseIf String.IsNullOrEmpty(value.Trim()) Then
			Return False
		End If

		For Each objChar In Path.GetInvalidPathChars()
			If value.IndexOf(objChar) > 0 Then
				Return False
			End If
		Next

		Return True

	End Function

	''' <summary>
	''' Checks if the specified value is a valid physical path.
	''' </summary>
	''' <returns>True if a valid physical path, otherwise False.</returns>
	Public Shared Function ValidatePhysicalPath(ByVal strPath As String) As Boolean

		If Not ValidatePath(strPath) Then
			Return False
		End If

		If strPath.IndexOf(Path.VolumeSeparatorChar) > 0 AndAlso (strPath.IndexOf(Path.DirectorySeparatorChar) > 0 Or strPath.IndexOf(Path.AltDirectorySeparatorChar) > 0) Then
			Return True
		Else
			Return False
		End If

	End Function

#End Region

#Region "Read"

	''' <summary>
	''' Reads the specified file using UTF8 and returns the contents as String.
	''' </summary>
	''' <returns>File contents as String.</returns>
	Public Shared Function ReadFile(ByVal strPath As String) As String

		Return ReadFile(strPath, Encoding.UTF8)

	End Function

	''' <summary>
	''' Reads a file using the specified encoding and returns the contents as String.
	''' </summary>
	''' <returns>File contents as String.</returns>
	Public Shared Function ReadFile(ByVal strPath As String, ByVal objEncoding As Encoding) As String

		Dim strReturn As String = String.Empty

		If File.Exists(strPath) Then

			Try

				Using objSR As StreamReader = New StreamReader(strPath, objEncoding)
					strReturn = objSR.ReadToEnd()
				End Using

			Catch
			End Try

		End If

		Return strReturn

	End Function

#End Region

#Region "Write"

	''' <summary>
	''' Writes contents to the specified file using UTF8, overwrites if exists.
	''' </summary>
	''' <returns>True if the write operation is successful, otherwise False.</returns>
	Public Shared Function WriteFile(ByVal strPath As String, ByVal strValue As String) As Boolean

		Return WriteFile(strPath, strValue, False, Encoding.UTF8)

	End Function

	''' <summary>
	''' Writes contents to the specified file using UTF8 (can overwrite or append).
	''' </summary>
	''' <returns>True if the write operation is successful, otherwise False.</returns>
	Public Shared Function WriteFile(ByVal strPath As String, ByVal strValue As String, ByVal blnAppend As Boolean) As Boolean

		Return WriteFile(strPath, strValue, blnAppend, Encoding.UTF8)

	End Function

	''' <summary>
	''' Writes contents to the specified file using a custom encoding (can overwrite or append).
	''' </summary>
	''' <returns>True if the write operation is successful, otherwise False.</returns>
	Public Shared Function WriteFile(ByVal strPath As String, ByVal strValue As String, ByVal blnAppend As Boolean, ByVal objEncoding As Encoding) As Boolean

		Dim blnReturn As Boolean

		Try

			If Not Directory.Exists(Path.GetDirectoryName(strPath)) Then
				Directory.CreateDirectory(Path.GetDirectoryName(strPath))
			End If

			Using objSW As StreamWriter = New StreamWriter(strPath, blnAppend, objEncoding)
				objSW.Write(strValue)
			End Using

			blnReturn = True

		Catch ex As Exception
			blnReturn = False
		End Try

		Return blnReturn

	End Function

#End Region

#Region "Copy"

	''' <summary>
	''' Copies the entire folder contents to the specified path, overwrites if exists.
	''' </summary>
	''' <returns>True if the copy operation is successful, otherwise False.</returns>
	Public Shared Function CopyFolder(ByVal strPathSrc As String, ByVal strPathDest As String) As Boolean

		Return CopyFolder(strPathSrc, strPathDest, True)

	End Function

	''' <summary>
	''' Copies the entire folder contents to the specified path (can overwrite or append).
	''' </summary>
	''' <returns>True if the copy operation is successful, otherwise False.</returns>
	Public Shared Function CopyFolder(ByVal strPathSrc As String, ByVal strPathDest As String, ByVal blnOverwrite As Boolean) As Boolean

		Dim blnReturn As Boolean = True
		Dim objDirSub As DirectoryInfo
		Dim objDirSrc As New DirectoryInfo(strPathSrc)
		Dim objDirDest As New DirectoryInfo(strPathDest)
		Dim objFileInfo As FileInfo

		Try

			If Not objDirDest.Exists Then
				objDirDest.Create()
			End If

			For Each objFileInfo In objDirSrc.GetFiles()
				objFileInfo.CopyTo(Path.Combine(objDirDest.FullName, objFileInfo.Name), blnOverwrite)
			Next

			For Each objDirSub In objDirSrc.GetDirectories()
				blnReturn = blnReturn And CopyFolder(objDirSub.FullName, Path.Combine(objDirDest.FullName, objDirSub.Name), blnOverwrite)
			Next

		Catch ex As Exception
			blnReturn = False
		End Try

		Return blnReturn

	End Function

#End Region

#Region "Get file information"

	''' <summary>
	''' Gets the size of the specified file in Kilobytes.
	''' </summary>
	''' <returns>File size in Kilobytes, as Int32.</returns>
	Public Shared Function GetFileSizeKbytes(ByVal strPath As String) As Integer

		Dim objFileInfo As New FileInfo(strPath)

		If objFileInfo.Exists Then
			Return Convert.ToInt32(objFileInfo.Length / 1024)
		Else
			Return 0
		End If

	End Function

	''' <summary>
	''' Gets the formatted size string for the specified file.
	''' </summary>
	''' <returns>Formatted file size as String.</returns>
	Public Shared Function GetSizeString(ByVal objFile As FileInfo) As String

		If objFile.Exists Then
			Return GetSizeString(objFile.Length \ 1024)
		Else
			Return "??? KB"
		End If

	End Function

	''' <summary>
	''' Gets the formatted size string for the specified value.
	''' </summary>
	''' <returns>Formatted size as String.</returns>
	Public Shared Function GetSizeString(ByVal intKBytes As Byte) As String

		Return (intKBytes) & " KB"

	End Function

	''' <summary>
	''' Gets the formatted size string for the specified value.
	''' </summary>
	''' <returns>Formatted size as String.</returns>
	Public Shared Function GetSizeString(ByVal intKBytes As Integer) As String

		Return GetSizeString(Convert.ToInt64(intKBytes))

	End Function

	''' <summary>
	''' Gets the formatted size string for the specified value.
	''' </summary>
	''' <returns>Formatted size as String.</returns>
	Public Shared Function GetSizeString(ByVal intKBytes As Long) As String

		If intKBytes < 1024 Then
			Return (intKBytes) & " KB"
		ElseIf intKBytes < 1024000 Then
			Return (intKBytes / 1024).ToString("0.00") & " MB"
		Else
			Return (intKBytes / 1024000).ToString("0.00") & " GB"
		End If

	End Function

	''' <summary>
	''' Counts how many files inside a particular folder.
	''' </summary>
	''' <returns>File count as Integer.</returns>
	Public Shared Function CountFiles(ByVal path As String) As Integer

		Return CountFiles(path, String.Empty)
		
	End Function

	''' <summary>
	''' Counts how many files that match the search filter inside a particular folder.
	''' </summary>
	''' <returns>File count as Integer.</returns>
	Public Shared Function CountFiles(ByVal path As String, ByVal filter As String) As Integer

		If (Not Directory.Exists(path)) Then
			Return 0
		End If

		Return Directory.GetFiles(path, filter).Length

	End Function

#End Region

End Class